// 提取value
type p = Promise<'xie'>
type GetValue<P> = P extends Promise<infer Value> ? Value : never
type P = GetValue<p>

/// 数组类型
// 提取数组第一个元素
type arr = [1,2,3]
type GetArrFirst<Arr extends number[]> = Arr extends [infer First, ...unknown[]] ? First : never
type first = GetArrFirst<arr>

// 提取除第一个的剩余数组
type PopArr<Arr extends number[]> = Arr extends [unknown, ...infer Pop] ? Pop : never
type pop = PopArr<arr>

/// 字符串类型
// 判断是否以某个字符串开头
type Name = 'xie'
type StartWith<Str extends string, PreString extends string> = Str extends `${PreString}${string}` ? true : false
type isStartWithX = StartWith<Name, 'x'>

// 字符串替换
type ReplaceStr<
  Str extends string,
  Form extends string,
  To extends string
> = Str extends `${infer Pre}${Form}${infer Suffix}`
? `${Pre}${To}${Suffix}`
: Str

type ReplaceName = ReplaceStr<Name, 'i', 'l'>

// 去掉字符串空格
// 因为不知道有多少个空格，所以需要递归去去除
// 去除右边空格
type TrimRightString<Str extends string> = Str extends `${infer Reset}${' ' | '\n' | '\t'}` ? TrimRightString<Reset> : Str
// 去除左边空格
type TrimLeftString<Str extends string> = Str extends `${' ' | '\n' | '\t'}${infer Reset}` ? TrimLeftString<Reset> : Str
type TrimString<Str extends string> = TrimLeftString<TrimRightString<Str>>
type trimString = TrimString<'   xie    '>

/// 函数
// 提取参数值
type Fun = (name: string, age: number) => string;
type GetParameters<Func extends Function> = Func extends (...arg: infer Arg) => unknown ? Arg : never;
type paramsRes = GetParameters<Fun>

// 提取返回值
type GetReturnType<Func extends Function> = Func extends (...arg: unknown[]) => infer ReturnType ? ReturnType : never;
// 开启了 strictFunctionTypes 关闭就可以了
type ReturnRes = GetReturnType<Fun>

// 提取this
type GetThisParameterType<T> = T extends (this: infer ThisType, ...arg: any[]) => any ? ThisType : unknown
class Xie {
  
}
function hello (this: Xie) {
  console.log(this)
}
// 获取函数的类型,用于下面的类型提取
type typeOfHello = typeof hello
type getThis = GetThisParameterType<typeof hello>

/// 构造器
// 构造器就是匹配函数基础上前面加个 new
// 提取构造器参数
type GetConstructorParameters<ConstructorType extends new (...args: any) => any> = ConstructorType extends new (...args: infer Params) => any ? Params : never;
interface Person {
  name: string
}
interface PersonConstructor {
  new(name: string): Person
}
type personParams = GetConstructorParameters<PersonConstructor>

// 总结
// TypeScript 类型的模式匹配是通过类型 extends 一个模式类型，把需要提取的部分放到通过 infer 声明的局部变量里，
// 后面可以从这个局部变量拿到类型做各种后续处理。